`timescale 1ns / 1ps
`include "defines.vh"
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2024/06/10 15:49:04
// Design Name: 
// Module Name: Regs
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module Regs (
    input [0:0] clk,
    input [0:0] rst,

    ////ID阶段

    input  [`Reg_Addr_Bus] Read_Reg_1_Addr_Input,// 读寄存器1地址
    output [`Reg_Data_Bus] Read_Reg_1_Data_Output,    // 读寄存器1值
    input  [`Reg_Addr_Bus] Read_Reg_2_Addr_Input,    // 读寄存器2地址
    output [`Reg_Data_Bus] Read_Reg_2_Data_Output,    // 读寄存器2值

    ////WB阶段
    input Write_Reg_Flag_Input,    // 写寄存器标志
    input [`Reg_Addr_Bus] Write_Reg_Addr_Input,    // 写寄存器地址
    input [`Reg_Data_Bus] Write_Reg_Data_Input    // 写寄存器值

);

    // 定义31个32位寄存器(第0位寄存器恒为0)
    reg [`Reg_Data_Bus] regs[1:`Reg_Num - 1];

    reg [`Reg_Data_Bus] Reg_1_Data_Output = `Regs_Rst;
    reg [`Reg_Data_Bus] Reg_2_Data_Output = `Regs_Rst;


    // 写寄存器时根据时钟信号写，读寄存器时直接读

    //复位寄存器操作
    // integer count = 0;
    // always @(posedge clk) begin
    //     if (rst == `Regs_Rst_Flag_Enabled) begin
    //         // 循环对1~31号寄存器复位
    //         for (count = 1; count < `Reg_Num; count = count + 1) begin
    //             regs[count] <= `Regs_Rst;
    //         end
    //     end
    // end



    //写寄存器
    always @(posedge clk) begin
        $display($time,"        Regs: Write_Flag:%d,  Write_Addr:%d,  Write_Data:%d",Write_Reg_Flag_Input,Write_Reg_Addr_Input,$signed(Write_Reg_Data_Input));
        // 若复位，不执行写命令
        if (rst != `Regs_Rst_Flag_Enabled) begin
            if(Write_Reg_Flag_Input == `Write_Reg_Flag_Enabled && Write_Reg_Addr_Input != `Reg_Zero_Addr)begin
                regs[Write_Reg_Addr_Input] <= Write_Reg_Data_Input;
            end
        end
    end

    //读寄存器1
    always @(*) begin
        // 若复位，输出寄存器复位默认值
        if (rst != `Regs_Rst_Flag_Enabled) begin
            // 若要进行写入，且写入地址与读取地址相同，则输出写入数据
            if(Write_Reg_Flag_Input == `Write_Reg_Flag_Enabled && Write_Reg_Addr_Input == Read_Reg_1_Addr_Input) begin
                Reg_1_Data_Output <= Write_Reg_Data_Input;
            end  // 不写入，不复位，直接读取
            else begin
                // 读取0号寄存器
                if (Read_Reg_1_Addr_Input == `Reg_Zero_Addr) begin
                    Reg_1_Data_Output <= `Reg_Zero_Data;
                end else begin
                    Reg_1_Data_Output <= regs[Read_Reg_1_Addr_Input];
                end
            end
        end else begin
            Reg_1_Data_Output <= `Regs_Rst;
        end
    end

    //读寄存器2
    always @(*) begin
        // 若复位，输出寄存器复位默认值
        if (rst != `Regs_Rst_Flag_Enabled) begin
            // 若要进行写入，且写入地址与读取地址相同，则输出写入数据
            if(Write_Reg_Flag_Input == `Write_Reg_Flag_Enabled && Write_Reg_Addr_Input == Read_Reg_2_Addr_Input) begin
                Reg_2_Data_Output <= Write_Reg_Data_Input;
            end  // 不写入，不复位，直接读取
            else begin
                // 读取0号寄存器
                if (Read_Reg_2_Addr_Input == `Reg_Zero_Addr) begin
                    Reg_2_Data_Output <= `Reg_Zero_Data;
                end else begin
                    Reg_2_Data_Output <= regs[Read_Reg_2_Addr_Input];
                end
            end
        end else begin
            Reg_2_Data_Output <= `Regs_Rst;
        end
    end


    assign Read_Reg_1_Data_Output = Reg_1_Data_Output;
    assign Read_Reg_2_Data_Output = Reg_2_Data_Output;

    always @(posedge clk) begin
        $display($time,"        Regs:  reg1:%d, reg2:%d, reg3:%d,reg4:%d, reg5:%d, reg6:%d,reg7:%d,reg8:%d  ...",$signed(regs[1]),$signed(regs[2]),$signed(regs[3]),$signed(regs[4]),$signed(regs[5]),$signed(regs[6]),$signed(regs[7]),$signed(regs[8]));
        $display($time,"        Regs:  Read_Reg_1:%d,%d, Read_Reg_2:%d,%d",Read_Reg_1_Addr_Input,$signed(Reg_1_Data_Output),Read_Reg_2_Addr_Input,$signed(Reg_2_Data_Output));
    end



endmodule
